﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.IO;
using IFont = iTextSharp.text.Font;
using System.Reflection;
using MossmanMill.DataModel;
using System.Windows.Forms;

namespace MossmanMill.Controller
{
    /// <summary>
    /// MCM PDF report manager class that create a PDF report from MCM database.
    /// </summary>
    /// <remarks>
    /// This class is thread safe. 
    /// </remarks>
    /// <dates>
    /// 17/05/2012 - created by Chiaki Sato
    /// </dates>
    class ReportManager : IReportManager
    {
        private string reportFileName;
        private IDatabaseAccess db;
        private List<Rack> dbRackList;
        private const int C200_TABLE_COLUMN_NUM = 4;


        /// <summary>
        /// Constructor for ReportManager class. 
        /// <param name="reportFileName">Report file name to create</param>
        /// </summary>
        public ReportManager(string reportFileName)
        {
            this.reportFileName = reportFileName;

            // Create Database Access by Factory
            IDBFactory dbFactory = new DBFactory();
            db = dbFactory.Make(DBFactory.CLASS_TYPE_DATABASE);

        }

        /// <summary>
        /// Create MCM PDF report from database data. 
        public void CreateReport()
        {
            // Create Document
            Document doc = new Document();

            try
            {

                // Set report file name 
                PdfWriter.GetInstance(doc, new FileStream(reportFileName, FileMode.Create));

                doc.Open();

                // Create Font
                IFont fontMainTitle = new IFont(IFont.FontFamily.TIMES_ROMAN, 24, IFont.BOLD);
                IFont fontLarge = new IFont(IFont.FontFamily.UNDEFINED, 10, IFont.NORMAL);

                doc.Add(new Paragraph("Mossman Central Mill Rack Report", fontMainTitle));
                doc.Add(new Paragraph(" "));
                doc.Add(new Paragraph(" "));

                DateTime dateTime = DateTime.Today;
                Paragraph paragraph = new Paragraph(dateTime.ToString("dd/MM/yyyy") + " Created by MCM Program.", fontLarge);
                paragraph.Alignment = Element.ALIGN_RIGHT;
                paragraph.IndentationRight = 8;
                doc.Add(paragraph);

                doc.Add(new Paragraph(" "));

                CreateC200RacksSection(doc);

                CreateCPMsSection(doc);

                doc.Close();

            }
            catch (IOException exception)
            {
                Console.WriteLine(MethodBase.GetCurrentMethod().Name + ": " + exception.ToString());
                doc.Close();
                throw exception;
            }
            catch (Exception exception)
            {
                Console.WriteLine(MethodBase.GetCurrentMethod().Name + ": " + exception.ToString());
                doc.Close();
                throw exception;
            }
        }

        private void CreateC200RacksSection(Document doc)
        {

            PdfPTable header1 = CreateHeader1("C200 Racks");
            doc.Add(header1);

            // Create Font
            IFont fontMainTitle = new IFont(IFont.FontFamily.TIMES_ROMAN, 24, IFont.BOLD);
            IFont fontHeading1 = new IFont(IFont.FontFamily.UNDEFINED, 16, IFont.BOLD);
            IFont fontHeading2 = new IFont(IFont.FontFamily.UNDEFINED, 12, IFont.BOLD);
            IFont fontLarge = new IFont(IFont.FontFamily.UNDEFINED, 10, IFont.NORMAL);
            IFont fontNormal = new IFont(IFont.FontFamily.UNDEFINED, 9, IFont.NORMAL);
            IFont fontSmall = new IFont(IFont.FontFamily.UNDEFINED, 7, IFont.NORMAL);

            doc.Add(new Paragraph(" "));
            dbRackList = db.GetRacks();

            List<RackLocal> rackFullNameList = GetRackFullNameList();

            foreach (RackLocal rackLocal in rackFullNameList)
            {
                doc.Add(new Paragraph(rackLocal.RackFullName, fontHeading2));
                doc.Add(new Paragraph(" "));

                PdfPTable table = new PdfPTable(C200_TABLE_COLUMN_NUM);
                PdfPCell cell;

                // Table Header
                cell = new PdfPCell(new Phrase("Slot No.", fontNormal));
                cell.GrayFill = 0.8f;
                table.AddCell(cell);
                cell = new PdfPCell(new Phrase("Equipment", fontNormal));
                cell.GrayFill = 0.8f;
                table.AddCell(cell);
                cell = new PdfPCell(new Phrase("Type", fontNormal));
                cell.GrayFill = 0.8f;
                table.AddCell(cell);
                cell = new PdfPCell(new Phrase("Slot ID", fontNormal));
                cell.GrayFill = 0.8f;
                table.AddCell(cell);

                List<Slottable> slotList = db.GetSlottables(rackLocal.Rack);

                if (slotList.Count != 0)
                {

                    int sparePostionFinder = 0;

                    foreach (Slottable slot in slotList)
                    {
                        int slotPosition = slot.Position;
                        int slotID = slot.SlotId;
                        char slotType = slot.SlotType;
                        string cardName = "";
                        string ioType = "";
                        string slotDetailID = "";

                        if (slot.Position > sparePostionFinder)
                        {

                            for (; sparePostionFinder < slot.Position; sparePostionFinder++)
                            {
                                cell = new PdfPCell(new Phrase(sparePostionFinder.ToString(), fontNormal));
                                table.AddCell(cell);
                                cell = new PdfPCell(new Phrase("", fontNormal));
                                table.AddCell(cell);
                                cell = new PdfPCell(new Phrase("SPARE", fontNormal));
                                table.AddCell(cell);
                                cell = new PdfPCell(new Phrase("", fontNormal));
                                table.AddCell(cell);
                            }

                        }
                        sparePostionFinder++;

                        if (slotType.CompareTo(char.Parse("N")) == 0)
                        {   // Network Card
                            cardName = "CCR011";
                            ioType = "CNI (SERVER)";
                        }
                        else if (slotType.CompareTo(char.Parse("C")) == 0)
                        {   // Card
                            Card card = db.GetCard(slotID, rackLocal.Rack.Id, slotPosition);
                            cardName = card.Name;

                            if (cardName.Length > 5)
                            {
                                // Get IO type
                                int posHyphen = cardName.IndexOf("-");
                                if (posHyphen >= 0)
                                {
                                    /// <param name="type">DO,DI,AO,AI,OTHER</param>
                                    /// <param name="channels">Number of channels</param>

                                    String ioTypeSubString = cardName.Substring(posHyphen + 1, 2);
                                    if (ioTypeSubString.CompareTo((@"IA")) == 0)
                                    {
                                        ioType = "AI";
                                        slotDetailID = "GSAIM0101" + String.Format("{0:D2}", slotPosition);
                                    }
                                    else if (ioTypeSubString.CompareTo((@"OA")) == 0)
                                    {
                                        ioType = "AO";
                                        slotDetailID = "GSAOM0101" + String.Format("{0:D2}", slotPosition);
                                    }
                                    else if (ioTypeSubString.CompareTo((@"ID")) == 0)
                                    {
                                        ioType = "DI";
                                        slotDetailID = "GSDOM0101" + String.Format("{0:D2}", slotPosition);
                                    }
                                    else if (ioTypeSubString.CompareTo((@"OD")) == 0)
                                    {
                                        ioType = "DO";
                                        slotDetailID = "GSDIM0101" + String.Format("{0:D2}", slotPosition);
                                    }
                                    else
                                    {
                                        ioType = "OTHER";
                                    }
                                }
                            }

                        }
                        else if (slotType.CompareTo(char.Parse("P")) == 0)
                        {   // Processor
                            cardName = "PRS021";
                            ioType = "PROCESSOR";
                        }

                        cell = new PdfPCell(new Phrase(slotPosition.ToString(), fontNormal));
                        table.AddCell(cell);
                        cell = new PdfPCell(new Phrase(cardName, fontNormal));
                        table.AddCell(cell);
                        cell = new PdfPCell(new Phrase(ioType, fontNormal));
                        table.AddCell(cell);
                        cell = new PdfPCell(new Phrase(slotDetailID, fontNormal));
                        table.AddCell(cell);

                    }

                    // Fill the trailing empty slots with the spare mark
                    if (12 > sparePostionFinder)
                    {

                        for (; sparePostionFinder < 12; sparePostionFinder++)
                        {
                            cell = new PdfPCell(new Phrase(sparePostionFinder.ToString(), fontNormal));
                            table.AddCell(cell);
                            cell = new PdfPCell(new Phrase("", fontNormal));
                            table.AddCell(cell);
                            cell = new PdfPCell(new Phrase("SPARE", fontNormal));
                            table.AddCell(cell);
                            cell = new PdfPCell(new Phrase("", fontNormal));
                            table.AddCell(cell);
                        }

                    }


                }
                else
                {

                    cell = new PdfPCell(new Phrase("0", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("CCR011", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("CNI (SERVER)", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("", fontNormal));
                    table.AddCell(cell);

                    cell = new PdfPCell(new Phrase("1", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("PRS021", fontNormal));
                    cell.Rowspan = 2;
                    cell.HorizontalAlignment = 0; //0=Left, 1=Centre, 2=Right
                    cell.VerticalAlignment = 1; //0=Left, 1=Centre, 2=Right
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("PROCESSOR", fontNormal));
                    cell.Rowspan = 2;
                    cell.HorizontalAlignment = 0; //0=Left, 1=Centre, 2=Right
                    cell.VerticalAlignment = 1; //0=Left, 1=Centre, 2=Right
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("", fontNormal));
                    cell.Rowspan = 2;
                    cell.HorizontalAlignment = 0; //0=Left, 1=Centre, 2=Right
                    cell.VerticalAlignment = 1; //0=Left, 1=Centre, 2=Right
                    table.AddCell(cell);

                    cell = new PdfPCell(new Phrase("2", fontNormal));
                    table.AddCell(cell);

                    cell = new PdfPCell(new Phrase("3", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("CCR011", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("CNI (PAN RTU)", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("", fontNormal));
                    table.AddCell(cell);

                    cell = new PdfPCell(new Phrase("4", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("TC-IAH161", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("AI", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("GSAIM010104", fontNormal));
                    table.AddCell(cell);

                    cell = new PdfPCell(new Phrase("5", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("TC-OAV081", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("AO", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("GSAOM010105", fontNormal));
                    table.AddCell(cell);

                    cell = new PdfPCell(new Phrase("6", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("TC-OAV081", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("AI", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("GSAOM010106", fontNormal));
                    table.AddCell(cell);

                    cell = new PdfPCell(new Phrase("7", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("TC-IAH161", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("AI", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("GSAIM010107", fontNormal));
                    table.AddCell(cell);

                    cell = new PdfPCell(new Phrase("8", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("SPARE", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("", fontNormal));
                    table.AddCell(cell);

                    cell = new PdfPCell(new Phrase("9", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("TC-ODJ161", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("DO", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("GSDOM010109", fontNormal));
                    table.AddCell(cell);

                    cell = new PdfPCell(new Phrase("10", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("TC-ODJ161", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("DI", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("GSDIM010110", fontNormal));
                    table.AddCell(cell);

                    cell = new PdfPCell(new Phrase("11", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("TC-IDJ161", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("DI", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("GSDIM010111", fontNormal));
                    table.AddCell(cell);

                    cell = new PdfPCell(new Phrase("12", fontNormal));
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("BATTERY", fontNormal));
                    cell.Colspan = 3;
                    cell.HorizontalAlignment = 0; //0=Left, 1=Centre, 2=Right
                    cell.VerticalAlignment = 1; //0=Left, 1=Centre, 2=Right
                    table.AddCell(cell);

                }
                doc.Add(table);

                doc.Add(new Paragraph(" "));

            }
        }

        private void CreateCPMsSection(Document doc)
        {
            // Create Font
            IFont fontHeading2 = new IFont(IFont.FontFamily.UNDEFINED, 12, IFont.BOLD);
            IFont fontNormal = new IFont(IFont.FontFamily.UNDEFINED, 8, IFont.NORMAL);
            PdfPTable table = null;
            PdfPCell cell;

            List<CpmReport> dbCpmReportList = db.GetCpmReport();

            string currentRackAddress = "";
            string currentRackFullName = "";

            foreach (CpmReport cpmReport in dbCpmReportList)
            {
                string rackFullName = cpmReport.Model + " " + cpmReport.Address + " - " + cpmReport.RoomName;

                if (currentRackAddress != cpmReport.Address)
                {
                    currentRackAddress = cpmReport.Address;

                    // Update tabel
                    if (table != null)
                    {
                        doc.Add(table);
                        table = null;
                    }

                    PdfPTable header1 = CreateHeader1(currentRackAddress);
                    doc.Add(new Paragraph(" "));
                    doc.Add(new Paragraph(" "));
                    doc.Add(header1);
                }

                // Table Header
                if (currentRackFullName != rackFullName || cpmReport.Channel == 0)
                {
                    currentRackFullName = rackFullName;

                    // Update tabel
                    if (table != null)
                    {
                        doc.Add(table);
                        table = null;
                    }

                    // Rack Sub Tiltle
                    doc.Add(new Paragraph(" "));
                    PdfPTable rackSubtitleTable = new PdfPTable(1);
                    PdfPCell rackSubtitleCell = new PdfPCell(new Phrase(currentRackFullName, fontHeading2));
                    rackSubtitleCell.Border = PdfPCell.NO_BORDER;
                    rackSubtitleCell.VerticalAlignment = PdfPCell.ALIGN_MIDDLE;
                    rackSubtitleCell.PaddingBottom = 2;
                    rackSubtitleTable.AddCell(rackSubtitleCell);
                    doc.Add(rackSubtitleTable);

                    table = new PdfPTable(5);
                    int[] widths = {24,26,32,9,9};
                    table.SetWidths(widths);
                    
                    // Table Header
                    cell = new PdfPCell(new Phrase("Tag No", fontNormal));
                    cell.GrayFill = 0.8f;
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("Param", fontNormal));
                    cell.GrayFill = 0.8f;
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("Description", fontNormal));
                    cell.GrayFill = 0.8f;
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("Slot", fontNormal));
                    cell.GrayFill = 0.8f;
                    table.AddCell(cell);
                    cell = new PdfPCell(new Phrase("Channel", fontNormal));
                    cell.GrayFill = 0.8f;
                    table.AddCell(cell);
                }

                cell = new PdfPCell(new Phrase(cpmReport.Tag, fontNormal));
                table.AddCell(cell);
                cell = new PdfPCell(new Phrase(cpmReport.Param, fontNormal));
                table.AddCell(cell);
                cell = new PdfPCell(new Phrase(cpmReport.Desc, fontNormal));
                table.AddCell(cell);
                cell = new PdfPCell(new Phrase(cpmReport.Position.ToString(), fontNormal));
                table.AddCell(cell);
                cell = new PdfPCell(new Phrase("Ch." + cpmReport.Channel.ToString(), fontNormal));
                table.AddCell(cell);
            }

            if (table != null)
            {
                doc.Add(table);
            }

        }

        private PdfPTable CreateHeader1(string header_title)
        {
            PdfPTable table = new PdfPTable(1);
            table.DefaultCell.Border = Rectangle.NO_BORDER;
            table.HorizontalAlignment = Element.ALIGN_LEFT;
            table.WidthPercentage = 100;
            PdfPCell cell;
            IFont fontHeading1Italic = new IFont(IFont.FontFamily.UNDEFINED, 16, IFont.BOLDITALIC);
            cell = new PdfPCell(new Phrase(header_title, fontHeading1Italic));
            cell.Border = PdfPCell.BOTTOM_BORDER;
            cell.BorderWidth = 2;
            cell.VerticalAlignment = Element.ALIGN_MIDDLE;
            cell.PaddingBottom = 4;
            table.AddCell(cell);

            return table;
        }

        private List<RackLocal> GetRackFullNameList()
        {

            List<RackLocal> rackFullNameList = new List<RackLocal>();

            int roomId = 0;

            foreach (Rack rack in dbRackList)
            {
                RackLocal rackLocal = new RackLocal(rack);

                string model = rack.Model;          // Model Name ex. C200
                string address = rack.Address;      // Rack Address ex. CPM0101
                roomId = rack.RoomId;               // Room ID ex. 1

                Room room = db.GetRoom(roomId);

                string roomName = room.Name;        // Get Room Name ex. Panstage

                // Complete Rack Full Name
                string rackFullName = model + " " + address + " (" + roomName + ")";

                rackLocal.RackFullName = rackFullName;

                rackFullNameList.Add(rackLocal);
            }

            return rackFullNameList;

        }

        private class RackLocal : Object
        {
            private string rackFullName;
            private Rack rack;

            public RackLocal(Rack rack)
            {
                this.rack = rack;
            }

            public Rack Rack
            {
                get { return rack; }
                set { rack = value; }
            }

            public string RackFullName
            {
                get { return rackFullName; }
                set { rackFullName = value; }
            }

        }

    }
}
